package com.jay.serializer;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jay.model.RpcRequest;
import com.jay.model.RpcResponse;

import java.io.IOException;

/**
 * Json 序列化器
 */
public class JsonSerializer implements Serializer {
    // Jackson 的 ObjectMapper 实例，用于 Json 序列化和反序列化
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Override
    public <T> byte[] serialize(T obj) throws IOException {
        // 使用 ObjectMapper 将对象序列化为 byte 数组
        return OBJECT_MAPPER.writeValueAsBytes(obj);
    }

    @Override
    public <T> T deserialize(byte[] bytes, Class<T> classType) throws IOException {
        // 使用 ObjectMapper 将 byte 数组反序列化为对象
        T obj = OBJECT_MAPPER.readValue(bytes, classType);
        // 如果反序列化对象是 RpcRequest 类型，进行特殊处理
        if (obj instanceof RpcRequest) {
            return handleRequest((RpcRequest) obj, classType);
        }
        // 如果反序列化对象是 RpcResponse 类型，进行特殊处理
        if (obj instanceof RpcResponse) {
            return handleResponse((RpcResponse) obj, classType);
        }
        // 对于其他类型，直接返回反序列化对象
        return obj;
    }

    /**
     * 由于 Object 的原始对象会被擦除，导致反序列化时会被作为 LinkedHashMap 无法转换成原始对象，因此这里做了特殊处理
     *
     * @param rpcRequest rpc 请求
     * @param type       类型
     * @return {@link T}
     * @throws IOException IO异常
     */
    private <T> T handleRequest(RpcRequest rpcRequest, Class<T> type) throws IOException {
        // 获取请求参数类型数组
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();
        // 获取请求参数值数组
        Object[] args = rpcRequest.getArgs();

        // 循环处理每个参数的类型
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> clazz = parameterTypes[i];
            // 如果类型不同，则重新处理一下类型
            if (!clazz.isAssignableFrom(args[i].getClass())) {
                // 将参数值序列化为 byte 数组
                byte[] argBytes = OBJECT_MAPPER.writeValueAsBytes(args[i]);
                // 将参数值反序列化为正确的类型
                args[i] = OBJECT_MAPPER.readValue(argBytes, clazz);
            }
        }
        // 将处理后的 RpcRequest 强制转换为指定类型并返回
        return type.cast(rpcRequest);
    }

    /**
     * 由于 Object 的原始对象会被擦除，导致反序列化时会被作为 LinkedHashMap 无法转换成原始对象，因此这里做了特殊处理
     *
     * @param rpcResponse rpc 响应
     * @param type        类型
     * @return {@link T}
     * @throws IOException IO异常
     */
    private <T> T handleResponse(RpcResponse rpcResponse, Class<T> type) throws IOException {
        // 将响应数据序列化为 byte 数组
        byte[] dataBytes = OBJECT_MAPPER.writeValueAsBytes(rpcResponse.getData());
        // 将响应数据反序列化为正确的类型
        rpcResponse.setData(OBJECT_MAPPER.readValue(dataBytes, rpcResponse.getDataType()));
        // 将处理后的 RpcResponse 强制转换为指定类型并返回
        return type.cast(rpcResponse);
    }
}
